// Copyright (c) 2009 Cloudage

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.

#include "stdafx.h"
#include "../luabindSensor/LuabindSensor.h"

#pragma region test namespace
namespace NamespaceA
{
	class ClassA
	{
	private:
		std::string m_property;

	public:
		enum EnumsA
		{
			E1,E2,E3,E4,E5
		};
		int field;
		const std::string& GetProperty()const
		{
			return m_property;
		}
		void SetProperty(const std::string& val)
		{
			m_property=val;
		}
		void Method(const std::string& msg)
		{
			std::cout<<msg<<std::endl;
		}
	};

	class ClassB
	{
	public:
		static void StaticMethodOfClassB(){}
	};

	void FreeFunction()
	{

	}

	namespace NamespaceB
	{
		void FreeFunction2(int a,bool b){}

		class ClassC
		{
		public:
			bool fieldOfClassC;
			int GetReadonlyProperty()const{return 100;}
		};
	}
}
#pragma endregion
#pragma region output helper
std::string GetIndent(int count)
{
	std::string ret;
	for(int i=0;i<count;i++)
		ret +="   ";
	return ret;
}

void Print(const LuabindSensor::ClassInfo::EnumItem& info,int indent)
{
	std::cout<<GetIndent(indent)<<"[Enum] "<<info.first<<" "<<info.second<<std::endl;
}

void Print(const LuabindSensor::FunctionInfo::SharePtr info,int indent)
{	
	std::cout<<GetIndent(indent)<<"["<<std::uppercase<<std::hex<<info->address<<"]"<<"[Function] "<<info->name<<" : "<<info->signature<<std::endl;
}

void Print(const LuabindSensor::PropertyInfo::SharePtr info,int indent)
{
	std::cout<<GetIndent(indent)<<"["<<std::uppercase<<std::hex<<info->address<<"]"<<"[Property] "<<info->name<<" : "<<info->typeName<<" "<<(info->isReadOnly?"ReadOnly":"ReadWrite")<<std::endl;
}

void Print(const LuabindSensor::ObjectInfo::SharePtr info,int indent)
{
	std::cout<<GetIndent(indent)<<"["<<std::uppercase<<std::hex<<info->address<<"]"<<"[Object] "<<info->name<<" : "<<(info->type.expired()?info->luaType:info->type.lock()->name)<<" "<<info->value<<std::endl;
}

void Print(const LuabindSensor::ClassInfo::SharePtr info,int indent)
{
	std::string idt = GetIndent(indent);
	std::cout<<idt<<"["<<std::uppercase<<std::hex<<info->address<<"]"<<"[Class] "<<info->name<<" "<<(info->isCppClass?"[Cpp Class]":"[Lua Class]")<<std::endl;
	
	std::cout<<idt<<"<enums>"<<std::endl;
	for(LuabindSensor::ClassInfo::EnumList::const_iterator i=info->enums.begin(),end=info->enums.end();i!=end;i++)
	{
		Print(*i,indent+1);
	}

	std::cout<<idt<<"<properties>"<<std::endl;
	for(LuabindSensor::PropertyInfo::List::const_iterator i=info->properties.begin(),end=info->properties.end();i!=end;i++)
	{
		Print(*i,indent+1);
	}

	std::cout<<idt<<"<methods>"<<std::endl;
	for(LuabindSensor::FunctionInfo::List::const_iterator i=info->methods.begin(),end=info->methods.end();i!=end;i++)
	{
		Print(*i,indent+1);
	}

	std::cout<<idt<<"<static methods>"<<std::endl;
	for(LuabindSensor::FunctionInfo::List::const_iterator i=info->staticMethods.begin(),end=info->staticMethods.end();i!=end;i++)
	{
		Print(*i,indent+1);
	}
}

void Print(const LuabindSensor::TableInfo::SharePtr info,int indent=0,bool expand = true)
{
	std::string idt = GetIndent(indent);
	std::cout<<idt<<"["<<std::uppercase<<std::hex<<info->address<<"]"<<"[Table] "<<info->name<<std::endl;
	
	if(expand)
	{
		std::cout<<idt<<"<sub tables>"<<std::endl;	
		for(LuabindSensor::TableInfo::List::const_iterator i=info->subTables.begin(),end=info->subTables.end();i!=end;i++)
		{
			Print(*i,indent+1);
		}

		std::cout<<idt<<"<sub reference tables>"<<std::endl;	
		for(LuabindSensor::TableInfo::List::const_iterator i=info->subTables.begin(),end=info->subTables.end();i!=end;i++)
		{
			Print(*i,indent+1,false);
		}

		std::cout<<idt<<"<classes>"<<std::endl;	
		for(LuabindSensor::ClassInfo::List::const_iterator i=info->classes.begin(),end=info->classes.end();i!=end;i++)
		{
			Print(*i,indent+1);
		}

		std::cout<<idt<<"<functions>"<<std::endl;	
		for(LuabindSensor::FunctionInfo::List::const_iterator i=info->functions.begin(),end=info->functions.end();i!=end;i++)
		{
			Print(*i,indent+1);
		}

		std::cout<<idt<<"<others>"<<std::endl;	
		for(LuabindSensor::ObjectInfo::List::const_iterator i=info->others.begin(),end=info->others.end();i!=end;i++)
		{
			Print(*i,indent+1);
		}
	}
}
#pragma endregion
int _tmain(int argc, _TCHAR* argv[])
{
	lua_State* l = lua_open();
	
	{
		using namespace luabind;
		
		open(l);
		luaL_openlibs(l);
		module(l)
			[
				namespace_("NamespaceA")
				[
					class_<NamespaceA::ClassA>("ClassA")
					.def(constructor<>())					
					.def_readwrite("field",&NamespaceA::ClassA::field)
					.property("Property",&NamespaceA::ClassA::GetProperty,&NamespaceA::ClassA::SetProperty)
					.def("Method",&NamespaceA::ClassA::Method)
					.enum_("EnumsA")
					[
						value("E1",NamespaceA::ClassA::E1),
						value("E2",NamespaceA::ClassA::E2),
						value("E3",NamespaceA::ClassA::E3),
						value("E4",NamespaceA::ClassA::E4),
						value("E5",NamespaceA::ClassA::E5)
					]
					,
					class_<NamespaceA::ClassB>("ClassB")
					.def(constructor<>())
					.scope
					[
						def("StaticMethodOfClassB",&NamespaceA::ClassB::StaticMethodOfClassB)
					]
					,
					def("FreeFunction",&NamespaceA::FreeFunction)
					,
					namespace_("NamespaceB")
					[
						class_<NamespaceA::NamespaceB::ClassC>("ClassC")
						.def_readonly("ReadonlyField",&NamespaceA::NamespaceB::ClassC::fieldOfClassC)
						.property("ReadonlyProperty",&NamespaceA::NamespaceB::ClassC::GetReadonlyProperty)
						,
						def("FreeFunction2",&NamespaceA::NamespaceB::FreeFunction2)
					]
				]
			];
	}

	LuabindSensor::TableInfo::SharePtr info = LuabindSensor::CreateAllDetail(l);

	//all informations are ready now,just get them via sensor->GetRoot() and show them up.
	Print(info);		

	lua_close(l);

	system("pause");

	return 0;
}

